package work.mediway.common.transport;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonInclude;

import org.apache.ibatis.type.Alias;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import work.mediway.common.domain.enums.CodeAndMsgEnum;
import work.mediway.common.page.Page;
import work.mediway.common.page.QueryRequest;

/**
 * 通用返回结果类
 *
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2019/11/1
 */
@SuppressWarnings("unchecked")
@ToString
@NoArgsConstructor
@Alias("CdrmpR")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class R<T> {

    public static final String WEBSERVICE_RESPONSE_DATA = "<Response><Header><SourceSystem>01</SourceSystem><MessageID></MessageID></Header><Body><ResultCode>{}</ResultCode><ResultContent>{}</ResultContent></Body></Response>";
    public static final long MIN_DATA_SIZE = 1L;
    public static final long NULL_DATA_SIZE = 0L;

    @ApiModelProperty(value = "返回值代码")
    @Setter
    @Getter
    private Integer code;

    @ApiModelProperty(value = "返回值消息")
    @Setter
    @Getter
    private String msg;

    @ApiModelProperty(value = "返回数据")
    @Setter
    @Getter
    private List<T> data;

    @ApiModelProperty(value = "返回数据")
    @Setter
    @Getter
    private Map<String, Object> other;

    @ApiModelProperty(value = "当前页")
    @Setter
    @Getter
    private Long draw;

    @ApiModelProperty(value = "页大小")
    @Setter
    @Getter
    private Long pageSize;

    @ApiModelProperty(value = "总页数")
    @Setter
    @Getter
    private Long pages;

    @ApiModelProperty(value = "数据总量")
    @Setter
    @Getter
    private Long total;


    /**
     * 成功但不带数据
     **/
    public static String successXml() {
        return StrUtil.format(WEBSERVICE_RESPONSE_DATA, CodeAndMsgEnum.WEBSERVICE_SUCCESS.getCode(), CodeAndMsgEnum.WEBSERVICE_SUCCESS.getMessage());
    }

    public static <T> R<T> success() {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        return result;
    }

    public static <T> R<T> success(String msg) {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(msg);
        return result;
    }

    public static <T> R<T> success(String msg, T data) {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setData(CollUtil.newArrayList(data));
        result.setMsg(msg);
        return result;
    }

    /**
     * 成功带数据
     **/
    public static <T> R<T> success(List<T> data) {
        R<T> result = new R<>();
        if (CollUtil.isEmpty(data)) {
            return failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
        }
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        result.setData(data);
        result.setDraw(MIN_DATA_SIZE);
        result.setPageSize(MIN_DATA_SIZE);
        result.setPages(MIN_DATA_SIZE);
        result.setTotal((long) data.size());
        return result;
    }

    /**
     * 成功带数据
     **/
    public static <T> R<T> success(Page<T> page) {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        if (CollUtil.isEmpty(page.getRecords())) {
            result.setCode(CodeAndMsgEnum.DB_RESOURCE_NULL.getCode());
            result.setMsg(CodeAndMsgEnum.DB_RESOURCE_NULL.getMessage());
        }
        result.setData(page.getRecords());
        result.setDraw(page.getCurrent());
        result.setPageSize(page.getSize());
        result.setPages(page.getPages());
        result.setTotal(page.getTotal());
        return result;
    }


    public static <T> R<T> success(List<T> data, Object object) {
        R<T> result = new R<>();
        if (ObjectUtil.isEmpty(object)) {
            return failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
        }
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        result.setData(data);
        result.setDraw(MIN_DATA_SIZE);
        result.setPageSize(MIN_DATA_SIZE);
        result.setPages(MIN_DATA_SIZE);
        result.setTotal(MIN_DATA_SIZE);
        if (object instanceof List) {
            result.setTotal((long) ((List<?>) object).size());
            if (CollUtil.isEmpty((List<T>) object)) {
                result = failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
            }
        }
        if (object instanceof Page<?>) {
            return result.success((Page<T>) object, result);
        }
        if (object instanceof IPage<?>) {
            return result.success((IPage<T>) object, result);
        }
        return result;
    }

    public static <T> R<T> success(List<T> data, QueryRequest queryRequest) {
        R<T> result = new R<>();
        if (CollUtil.isEmpty(data)) {
            return failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
        }
        int totalPage = 0;
        int total = data.size();
        if (total % queryRequest.getPageSize() == 0) {
            totalPage = total / queryRequest.getPageSize();
        } else {
            totalPage = total / queryRequest.getPageSize() + 1;
        }
        List<T> collect = data.stream()
                .skip((queryRequest.getPageNumber() - 1) * queryRequest.getPageSize())
                .limit(queryRequest.getPageSize())
                .collect(Collectors.toList());
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        result.setData(collect);
        result.setDraw(Long.valueOf(queryRequest.getPageNumber()));
        result.setPageSize(Long.valueOf(queryRequest.getPageSize()));
        result.setPages(Long.valueOf(totalPage));
        result.setTotal(Long.valueOf(total));
        return result;
    }

    private R<T> success(IPage<T> page, R<T> result) {

        if (ObjectUtil.isEmpty(page)) {
            return failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
        }
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        result.setData(CollUtil.isNotEmpty(result.getData()) ? result.getData() : page.getRecords());
        result.setDraw(page.getCurrent());
        result.setPageSize(page.getSize());
        result.setPages(page.getPages());
        result.setTotal(page.getTotal());

        if (CollUtil.isEmpty(page.getRecords())) {
            result = failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
        }
        return result;
    }

    public static <T> R<T> success(Object data) {
        if (data instanceof Page) {
            return success(((Page<T>) data).getRecords(), data);
        } else if (data instanceof List) {
            return success((List<T>) data);
        } else {
            return success("", (T) data);
        }
    }

    private R<T> success(Page<T> page, R<T> result) {
        if (ObjectUtil.isEmpty(page)) {
            return failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
        }
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        result.setData(CollUtil.isNotEmpty(result.getData()) ? result.getData() : page.getRecords());
        result.setDraw(page.getCurrent());
        result.setPageSize(page.getSize());
        result.setPages(page.getPages());
        result.setTotal(page.getTotal());

        if (CollUtil.isEmpty(page.getRecords())) {
            result = failed(CodeAndMsgEnum.DB_RESOURCE_NULL);
        }
        return result;
    }


    /**
     * 操作失败
     *
     * @return ResponseDTO
     */
    public static String failedXml() {
        return StrUtil.format(WEBSERVICE_RESPONSE_DATA, CodeAndMsgEnum.WEBSERVICE_ERROR.getCode(), CodeAndMsgEnum.WEBSERVICE_ERROR.getMessage());
    }

    public static <T> R<T> failed() {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.FAIL.getMessage());
        result.setData(CollUtil.newArrayList());
        result.setDraw(NULL_DATA_SIZE);
        result.setPageSize(NULL_DATA_SIZE);
        result.setPages(NULL_DATA_SIZE);
        result.setTotal(NULL_DATA_SIZE);
        return result;
    }

    /**
     * 失败
     **/
    public static <T> R<T> failed(Integer code, String msg) {
        R<T> result = new R<>();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(CollUtil.newArrayList());
        result.setDraw(NULL_DATA_SIZE);
        result.setPageSize(NULL_DATA_SIZE);
        result.setPages(NULL_DATA_SIZE);
        result.setTotal(NULL_DATA_SIZE);
        return result;
    }

    public static <T> R<T> failed(String message) {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.FIELD_INCOMPLETE.getCode());
        result.setMsg(message);
        result.setData(CollUtil.newArrayList());
        result.setDraw(NULL_DATA_SIZE);
        result.setPageSize(NULL_DATA_SIZE);
        result.setPages(NULL_DATA_SIZE);
        result.setTotal(NULL_DATA_SIZE);
        return result;
    }

    public static <T> R<T> failed(CodeAndMsgEnum resultCodeEnum) {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(resultCodeEnum.getMessage());
        result.setData(CollUtil.newArrayList());
        result.setDraw(NULL_DATA_SIZE);
        result.setPageSize(NULL_DATA_SIZE);
        result.setPages(NULL_DATA_SIZE);
        result.setTotal(NULL_DATA_SIZE);
        return result;
    }

    /**
     * 设置响应
     *
     * @param response    HttpServletResponse
     * @param contentType content-type
     * @param status      http状态码
     * @param value       响应内容
     * @throws IOException IOException
     */
    public static void makeResponse(HttpServletResponse response, String contentType,
                                    int status, Object value) throws IOException {
        response.setContentType(contentType);
        response.setStatus(status);
        response.setCharacterEncoding("UTF-8");
        response.getOutputStream().write(JSONUtil.toJsonStr(value).getBytes(StandardCharsets.UTF_8));
    }

    public static void makeResponse(HttpServletResponse response, String contentType,
                                    int status, byte[] value) throws IOException {
        response.setContentType(contentType + ";charset=UTF-8");
        response.setStatus(status);
        response.setCharacterEncoding("UTF-8");
        response.getOutputStream().write(value);
    }

    public static <T> R<T> successWithOther(List<T> object, Map<String, Object> other) {
        R<T> result = new R<>();
        result.setCode(CodeAndMsgEnum.SUCCESS.getCode());
        result.setMsg(CodeAndMsgEnum.SUCCESS.getMessage());
        result.setData(object);
        result.setOther(other);
        result.setDraw(MIN_DATA_SIZE);
        result.setPageSize(MIN_DATA_SIZE);
        result.setPages(MIN_DATA_SIZE);
        result.setTotal(MIN_DATA_SIZE);
        return result;
    }

    /**
     * 失败
     **/
    public static <T> R<T> error(Integer code, String msg) {
        R<T> result = new R<>();
        result.setCode(code);
        result.setMsg(msg);
        result.setDraw(NULL_DATA_SIZE);
        result.setPageSize(NULL_DATA_SIZE);
        result.setPages(NULL_DATA_SIZE);
        result.setTotal(NULL_DATA_SIZE);
        return result;
    }

    /*public static void download(HttpServletResponse response, String fileName, Class<?> clz, List<?> data) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String file = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + file + CdrMPConstant.VALID_FILE_TYPE[0]);
        EasyExcel.write(fileName, clz)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet(fileName).doWrite(data);
    }*/

}














